package com.happy.cat.project.system.service.impl;

import cn.hutool.json.JSONUtil;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.StringUtils;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyun.oss.model.PutObjectRequest;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.happy.cat.common.utils.SecurityUtils;
import com.happy.cat.common.utils.StringFormater;
import com.happy.cat.framework.config.properties.AliOssConfig;
import com.happy.cat.project.system.service.ICatAliOssService;
import com.happy.cat.project.system.domain.CatResource;
import com.happy.cat.project.system.domain.OssCallbackParam;
import com.happy.cat.project.system.domain.OssPolicyResultVo;
import com.happy.cat.project.system.service.ICatResourceService;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

/**
 * @Author: verne
 * @Data: 2020/7/27 15:40
 */
@Service
public class ICatAliOssServiceImpl implements ICatAliOssService {

    @Autowired
    private AliOssConfig oss;

    @Autowired
    private ICatResourceService resourceService;

    private DefaultIdentifierGenerator idGenerator=new DefaultIdentifierGenerator();

    @Override
    public CatResource storeFile(MultipartFile multpartFile, String resType, String subFix) throws IOException {
        CatResource resource=new CatResource();
        resource.setId(idGenerator.nextId(resource));
        resource.setResType(resType);
        resource.setCreateTime(new Date());
        resource.setCreateBy(SecurityUtils.getUsername());
        String uri= StringFormater.format("{}/{}/{}.{}",oss.getUploadDir(), resType,resource.getId(),subFix);
        String resValue=null;
        try(InputStream input=multpartFile.getInputStream()){
            if(oss.isOssFlag()) {
                resValue=uploadFileToOss(uri, input);
            }else {
                resValue=uploadFileToLocal(uri,input);
            }
        }
        resource.setResValue(resValue);
        return resource;
    }

    @Override
    public OssPolicyResultVo policy(String resType,String subFix) {
        CatResource resource=new CatResource();
        resource.setId(idGenerator.nextId(resource));
        String ossPath = StringFormater.format("{}/{}/{}/{}.{}",oss.getOssDir(),oss.getUploadDir(), resType,resource.getId(),subFix);
        DefaultCredentialProvider defaultCredentialProvider=new DefaultCredentialProvider(oss.getAccessKeyId(), oss.getAccessKeySecret());
        OSSClient ossClient = new OSSClient(oss.getEndpoint(), defaultCredentialProvider, new ClientBuilderConfiguration());
        OssPolicyResultVo result = new OssPolicyResultVo();
        // 签名有效期
        Date expiration = new Date(System.currentTimeMillis() + oss.getOssExpire() * 1000);

        // 文件大小
        long maxSize = oss.getOssMaxSize() * 1024 * 1024;

        // 回调
        OssCallbackParam callback = new OssCallbackParam();

        callback.setCallbackUrl(oss.getOssCallback());
        callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}" +
                "&width=${imageInfo.width}&file_id=${x:file_id}&file_type=${x:file_type}&file_text=${x:file_text}");
        callback.setCallbackBodyType("application/x-www-form-urlencoded");
        // 提交节点
        String action = StringFormater.format("{}://{}.{}", oss.getHttp(),oss.getBuckname(),oss.getEndpoint());
        try {

            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, ossPath);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String policy = BinaryUtil.toBase64String(binaryData);
            String signature = ossClient.calculatePostSignature(postPolicy);
            String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("utf-8"));

            // 返回结果
            result.setOssAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
            result.setPolicy(policy);
            result.setSignature(signature);
            result.setDir(ossPath);
            result.setCallback(callbackData);
            result.setHost(action);
            result.setFileId(resource.getId());
            result.setFileType(resType);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ossClient.shutdown();
        }
        return result;
    }

    @Override
    public CatResource callback(HttpServletRequest request) {
        String fileId = request.getParameter("file_id");
        if(StringUtils.isNullOrEmpty(fileId)){
            return null;
        }
        String filename = request.getParameter("filename");
        if(StringUtils.isNullOrEmpty(filename)){
            return null;
        }
        String resType = request.getParameter("file_type");
        if(StringUtils.isNullOrEmpty(resType)){
            return null;
        }
        filename = StringFormater.format("{}/{}", oss.getCdnUrl(),filename);
        CatResource resource= new CatResource();
        resource.setId(Long.parseLong(fileId));
        resource.setResValue(filename);
        resource.setResType(resType);
        resourceService.save(resource);
        return resource;
    }

    /**
     * 上传到服务器
     * @param uri
     * @param inputStream
     * @return
     * @throws IOException
     */
    private String uploadFileToLocal(String uri,InputStream inputStream) throws IOException {
        FileUtils.copyInputStreamToFile(inputStream, new File(oss.getFilePath().getFile(),uri));
        return oss.getStaticUrl()+'/'+uri;
    }

    /**
     * 上传到OSS
     * @param uri
     * @param inputStream
     * @return
     */
    private String uploadFileToOss(String uri, InputStream inputStream) {
        DefaultCredentialProvider defaultCredentialProvider=new DefaultCredentialProvider(oss.getAccessKeyId(), oss.getAccessKeySecret());
        String ossPath=StringFormater.format("{}/{}",oss.getOssDir(),uri);
        OSSClient ossClient = new OSSClient(oss.getEndpoint(), defaultCredentialProvider, new ClientBuilderConfiguration());
        ossClient.putObject(new PutObjectRequest(oss.getBuckname(), ossPath, inputStream));
        ossClient.shutdown();
        return StringFormater.format("{}/{}", oss.getCdnUrl(),ossPath);
    }


}
